using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Xml.Linq;
using UtilZ.Dotnet.Ex.Model;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// Convert类型扩展方法类
    /// </summary>
    public static partial class ConvertEx
    {

        #region 十六进制字符串与二进制数据相互转换

        private const char _spacebar = ' ';
#if CORE
        /// <summary>
        /// 十六进制字符串转换为的二进制数据
        /// </summary>
        /// <param name="str">十六进制字符串转</param>
        /// <returns>二进制数据</returns>
        public static byte[] HexadecimaStringToBytes(ReadOnlyMemory<char> str)
        {
            if (str.IsEmpty)
            {
                return null;
            }

            str = str.Trim(_spacebar);
            bool has0x = str.Span.Contains('x');
            byte value;
            byte[] buffer;
            ReadOnlySpan<char> temp;

            if (str.Span.Contains(_spacebar))
            {
                const int _DEFAULT_INDEX = -1;
                int beginIndex = _DEFAULT_INDEX;
                int lastIndex = str.Length - 1;
                int capacity;
                List<byte> list;

                if (has0x)
                {
                    //0xaa 0x12 0x34 0xbc
                    //正常情况下，结果数据应=(字符长度+1)/5,再向上浮动4个，以提升效率，减少list扩容
                    capacity = (str.Length + 1) / 5 + 4;
                    list = new List<byte>(capacity);
                    for (int i = 0; i < str.Length; i++)
                    {
                        if (str.Span[i] == _spacebar || i == lastIndex)
                        {
                            if (beginIndex == _DEFAULT_INDEX)
                            {
                                //连续空格，忽略
                                continue;
                            }
                            else
                            {
                                if (i == lastIndex)
                                {
                                    temp = str.Span.Slice(beginIndex + 2);
                                }
                                else
                                {
                                    temp = str.Span.Slice(beginIndex + 2, 2);
                                }

                                beginIndex = _DEFAULT_INDEX;
                                if (byte.TryParse(temp, System.Globalization.NumberStyles.HexNumber, null, out value))
                                {
                                    list.Add(value);
                                }
                                else
                                {
                                    throw new ArgumentException($"无效的字符\"{new string(temp)}\"");
                                }
                            }
                        }
                        else
                        {
                            if (beginIndex == _DEFAULT_INDEX)
                            {
                                beginIndex = i;
                            }
                        }
                    }
                }
                else
                {
                    //aa 12 34 bc
                    //正常情况下，结果数据应=字符长度/3,再向上浮动4个，以提升效率，减少list扩容
                    capacity = str.Length / 3 + 4;
                    list = new List<byte>(capacity);
                    for (int i = 0; i < str.Length; i++)
                    {
                        if (str.Span[i] == _spacebar || i == lastIndex)
                        {
                            if (beginIndex == _DEFAULT_INDEX)
                            {
                                //连续空格，忽略
                                continue;
                            }
                            else
                            {
                                if (i == lastIndex)
                                {
                                    temp = str.Span.Slice(beginIndex);
                                }
                                else
                                {
                                    temp = str.Span.Slice(beginIndex, i - beginIndex);
                                }
                                beginIndex = _DEFAULT_INDEX;
                                if (byte.TryParse(temp, System.Globalization.NumberStyles.HexNumber, null, out value))
                                {
                                    list.Add(value);
                                }
                                else
                                {
                                    throw new ArgumentException($"无效的字符\"{new string(temp)}\"");
                                }
                            }
                        }
                        else
                        {
                            if (beginIndex == _DEFAULT_INDEX)
                            {
                                beginIndex = i;
                            }
                        }
                    }
                }
                buffer = list.ToArray();
            }
            else
            {
                if (str.Length % 2 != 0)
                {
                    throw new ArgumentException("待转换的字符串长度不能为奇数");
                }

                int index = 0;
                if (has0x)
                {
                    //0xaa0x120x340xbc
                    buffer = new byte[str.Length / 4];
                    for (int i = 0; i < str.Length; i += 4)
                    {
                        temp = str.Span.Slice(i + 2, 2);
                        if (byte.TryParse(temp, System.Globalization.NumberStyles.HexNumber, null, out value))
                        {
                            buffer[index++] = value;
                        }
                        else
                        {
                            throw new ArgumentException($"无效的字符\"{new string(temp)}\"");
                        }
                    }
                }
                else
                {
                    //aa1234bc
                    buffer = new byte[str.Length / 2];
                    for (int i = 0; i < str.Length; i += 2)
                    {
                        temp = str.Span.Slice(i, 2);
                        if (byte.TryParse(temp, System.Globalization.NumberStyles.HexNumber, null, out value))
                        {
                            buffer[index++] = value;
                        }
                        else
                        {
                            throw new ArgumentException($"无效的字符\"{new string(temp)}\"");
                        }
                    }
                }
            }

            return buffer;
        }

        /// <summary>
        /// byte数组转换为16进制字符串
        /// </summary>
        /// <param name="span">byte数据</param>
        /// <param name="has0x">16进制数是否包含0x[true:包含0x;false:不包含0x]</param>
        /// <param name="splitChar">分隔字符</param>
        /// <returns>16进制字符串</returns>
        public static string BytesToHexadecimaString(in Span<byte> span, bool has0x = false, char? splitChar = _spacebar)
        {
            if (span.Length == 0)
            {
                return null;
            }

            StringBuilder sb = new StringBuilder();
            string str;

            for (int i = 0; i < span.Length; i++)
            {
                if (has0x)
                {
                    sb.Append("0x");
                }

                str = Convert.ToString(span[i], 16);
                if (str.Length == 1)
                {
                    sb.Append('0');
                }

                sb.Append(str);
                if (splitChar.HasValue)
                {
                    sb.Append(splitChar.Value);
                }
            }

            return sb.ToString();
        }

#endif
        /// <summary>
        /// byte数组转换为16进制字符串
        /// </summary>
        /// <param name="span">byte数据</param>
        /// <param name="has0x">16进制数是否包含0x[true:包含0x;false:不包含0x]</param>
        /// <param name="splitChar">分隔字符</param>
        /// <returns>16进制字符串</returns>
        public static string BytesToHexadecimaString(SpanZ<byte> span, bool has0x = false, char? splitChar = _spacebar)
        {
            if (span.Length == 0)
            {
                return null;
            }

            StringBuilder sb = new StringBuilder();
            string str;

            for (int i = 0; i < span.Length; i++)
            {
                if (splitChar.HasValue && sb.Length > 0)
                {
                    sb.Append(splitChar.Value);
                }

                if (has0x)
                {
                    sb.Append("0x");
                }

                str = Convert.ToString(span[i], 16);
                if (str.Length == 1)
                {
                    sb.Append('0');
                }

                sb.Append(str);
            }

            return sb.ToString();
        }

        /// <summary>
        /// byte数组转换为16进制字符串
        /// </summary>
        /// <param name="buffer">byte数组</param>
        /// <param name="has0x">16进制数是否包含0x[true:包含0x;false:不包含0x]</param>
        /// <param name="splitChar">分隔字符</param>
        /// <returns>16进制字符串</returns>
        public static string BytesToHexadecimaString(byte[] buffer, bool has0x = false, char? splitChar = _spacebar)
        {
            return BytesToHexadecimaString(buffer, -1, -1, has0x, splitChar);
        }

        /// <summary>
        /// byte数组转换为16进制字符串
        /// </summary>
        /// <param name="buffer">byte数组</param>
        /// <param name="index">byte数组中的起始位置,小于0表示从头开始</param>
        /// <param name="count">byte数组中的byte个数,小于0表示到结尾</param>
        /// <param name="has0x">16进制数是否包含0x[true:包含0x;false:不包含0x]</param>
        /// <param name="splitChar">分隔字符</param>
        /// <returns>16进制字符串</returns>
        public static string BytesToHexadecimaString(byte[] buffer, int index, int count, bool has0x = false, char? splitChar = _spacebar)
        {
            if (buffer == null || buffer.Length == 0)
            {
                return null;
            }

            if (index < 0)
            {
                index = 0;
            }

            if (count < 0)
            {
                count = buffer.Length - index;
            }

            if (index >= buffer.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(index));
            }

            int endIndex = index + count;
            if (endIndex > buffer.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            StringBuilder sb = new StringBuilder();
            string str;

            for (int i = index; i < endIndex; i++)
            {
                if (has0x)
                {
                    sb.Append("0x");
                }

                str = Convert.ToString(buffer[i], 16);
                if (str.Length == 1)
                {
                    sb.Append('0');
                }

                sb.Append(str);
                if (splitChar.HasValue)
                {
                    sb.Append(splitChar.Value);
                }
            }

            return sb.ToString();
        }







        /// <summary>
        /// 十六进制字符串转换为的二进制数据,并返回转换数据长度
        /// </summary>
        /// <param name="hexStr">十六进制字符串转</param>
        /// <param name="buffer">二进制数据buffer</param>
        /// <returns>转换数据长度</returns>
        public static int HexadecimaStringToBytes(string hexStr, SpanZ<byte> buffer)
        {
            return HexadecimaStringToBytes(hexStr, buffer.ToSpan());
        }

        /// <summary>
        /// 十六进制字符串转换为的二进制数据,并返回转换数据长度
        /// </summary>
        /// <param name="hexStr">十六进制字符串转</param>
        /// <param name="buffer">二进制数据buffer</param>
        /// <returns>转换数据长度</returns>
        unsafe public static int HexadecimaStringToBytes(string hexStr, byte[] buffer)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

#if NET4_0
            fixed (byte* dataPtr = buffer)
            {
                return HexadecimaStringToBytes(hexStr, new Span<byte>(dataPtr, buffer.Length));
            }
#else
            return HexadecimaStringToBytes(hexStr, new Span<byte>(buffer));
#endif
        }

        /// <summary>
        /// 十六进制字符串转换为的二进制数据
        /// </summary>
        /// <param name="hexStr">十六进制字符串转</param>
        /// <param name="buffer">二进制数据buffer</param>
        /// <returns>转换数据长度</returns>
        public static int HexadecimaStringToBytes(string hexStr, Span<byte> buffer)
        {
            if (string.IsNullOrWhiteSpace(hexStr))
            {
                return 0;
            }

            int index = 0;
            int charIndex = 0, charIndex2;

            if (hexStr.Any((ch) => { return ch == 'x' || ch == 'X'; }))
            {
                //包含0x
                while (index < buffer.Length && charIndex < hexStr.Length)
                {
                    while (hexStr[charIndex] == ' ' || hexStr[charIndex] == '\r' || hexStr[charIndex] == '\n')
                    {
                        charIndex++;
                    }

                    charIndex2 = charIndex + 1;
                    while (charIndex2 < hexStr.Length && hexStr[charIndex] == '0' && (hexStr[charIndex2] == 'x' || hexStr[charIndex2] == 'X'))
                    {
                        charIndex += 2;
                        charIndex2 = charIndex + 1;
                    }

                    if (charIndex2 >= hexStr.Length)
                    {
                        break;
                    }

                    buffer[index] = (byte)((HexCharToInt32(hexStr[charIndex]) << 4) | HexCharToInt32(hexStr[charIndex2]));
                    index++;
                    charIndex += 2;
                }
            }
            else
            {
                //不包含0x
                while (index < buffer.Length && charIndex < hexStr.Length)
                {
                    while (charIndex < hexStr.Length &&
                        (hexStr[charIndex] == ' ' || hexStr[charIndex] == '\r' || hexStr[charIndex] == '\n'))
                    {
                        charIndex++;
                    }

                    charIndex2 = charIndex + 1;
                    if (charIndex2 >= hexStr.Length)
                    {
                        break;
                    }

                    buffer[index] = (byte)((HexCharToInt32(hexStr[charIndex]) << 4) | HexCharToInt32(hexStr[charIndex2]));
                    index++;
                    charIndex += 2;
                }
            }

            return index;
        }

#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        private static int HexCharToInt32(char ch)
        {
            //num3 = ((*ptr >= '0' && *ptr <= '9') ? (num3 + (uint)(*ptr - 48)) : ((*ptr < 'A' || *ptr > 'F') ? (num3 + (uint)(*ptr - 97 + 10)) : (num3 + (uint)(*ptr - 65 + 10))));
            int result;
            if (ch >= '0' && ch <= '9')
            {
                result = ch - 48;
            }
            else if (ch >= 'A' && ch <= 'F')
            {
                result = ch - 55;
            }
            else if (ch >= 'a' && ch <= 'f')
            {
                result = ch - 87;
            }
            else
            {
                throw new ArgumentException($"无效的字符\"{ch}\"");
            }

            return result;
        }

        /// <summary>
        /// 十六进制字符串转换为的二进制数据
        /// </summary>
        /// <param name="hexStr">十六进制字符串转</param>
        /// <returns>二进制数据</returns>
        public static byte[] HexadecimaStringToBytes(string hexStr)
        {
            if (string.IsNullOrWhiteSpace(hexStr))
            {
                return null;
            }

            hexStr = hexStr.Trim(' ');
            bool has0x = hexStr.Any((ch) => { return ch == 'x' || ch == 'X'; });
            byte[] buffer;
            if (hexStr.Contains(' '))
            {
                string[] strArr = hexStr.Split(new char[] { ' ', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                buffer = new byte[strArr.Length];

                if (has0x)
                {
                    //0xaa 0x12 0x34 0xbc
                    for (int i = 0; i < buffer.Length; i++)
                    {
                        buffer[i] = Convert.ToByte(strArr[i], 16);
                    }
                }
                else
                {
                    //aa 12 34 bc
                    for (int i = 0; i < buffer.Length; i++)
                    {
                        buffer[i] = Convert.ToByte($"0x{strArr[i]}", 16);
                    }
                }
            }
            else
            {
                if (hexStr.Length % 2 != 0)
                {
                    throw new ArgumentException("待转换的字符串长度不能为奇数");
                }

                string tempStr;
                int index = 0;
                if (has0x)
                {
                    //0xaa0x120x340xbc
                    buffer = new byte[hexStr.Length / 4];
                    for (int i = 0; i < hexStr.Length; i += 4)
                    {
                        tempStr = hexStr.Substring(i + 2, 2);
                        buffer[index++] = Convert.ToByte(tempStr, 16);
                    }
                }
                else
                {
                    //aa1234bc
                    buffer = new byte[hexStr.Length / 2];
                    for (int i = 0; i < hexStr.Length; i += 2)
                    {
                        tempStr = hexStr.Substring(i, 2);
                        buffer[index++] = Convert.ToByte(tempStr, 16);
                    }
                }
            }

            return buffer;
        }




        /// <summary>
        /// 十六进制字符串转换为字符串
        /// </summary>
        /// <param name="hexadecimaStr">十六进制字符串</param>
        /// <param name="encoding">字符编码,为null默认用不用utf-8编码</param>
        /// <returns>字符串</returns>
        public static string HexadecimaStringToString(string hexadecimaStr, Encoding encoding = null)
        {
            byte[] buffer = HexadecimaStringToBytes(hexadecimaStr);
            if (buffer == null)
            {
                return null;
            }

            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }

            return encoding.GetString(buffer);
        }

        #endregion


        #region 整数转换为十六进制格式字符串
        ///// <summary>
        ///// 转换为十六进制字符串
        ///// </summary>
        ///// <typeparam name="T">具体的某种整形值类型</typeparam>
        ///// <param name="value">十进制整形数值</param>
        ///// <returns>0x开头的十六进制字符串</returns>
        //public static string ToHexadecimaString<T>(this T value) where T : struct, IFormattable
        //{
        //    return string.Format("0x{0}", value.ToString("x4", null));
        //}

        /// <summary>
        /// byte转换为十六进制格式字符串 
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>十六进制格式字符串 </returns>
        public static string ToHexadecimaString(this byte value)
        {
            //return $"0x{Convert.ToString(value, 16)}";
            return $"0x{value.ToString("x")}";
        }

        /// <summary>
        /// sbyte转换为十六进制格式字符串 
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>十六进制格式字符串 </returns>
        public static string ToHexadecimaString(this sbyte value)
        {
            return $"0x{value.ToString("x")}";
        }

        /// <summary>
        /// short转换为十六进制格式字符串 
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>十六进制格式字符串 </returns>
        public static string ToHexadecimaString(this short value)
        {
            return $"0x{value.ToString("x")}";
        }

        /// <summary>
        /// ushort转换为十六进制格式字符串 
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>十六进制格式字符串 </returns>
        public static string ToHexadecimaString(this ushort value)
        {
            return $"0x{value.ToString("x")}";
        }

        /// <summary>
        /// int转换为十六进制格式字符串 
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>十六进制格式字符串 </returns>
        public static string ToHexadecimaString(this int value)
        {
            return $"0x{value.ToString("x")}";
        }

        /// <summary>
        /// uint转换为十六进制格式字符串 
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>十六进制格式字符串 </returns>
        public static string ToHexadecimaString(this uint value)
        {
            return $"0x{value.ToString("x")}";
        }

        /// <summary>
        /// long转换为十六进制格式字符串 
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>十六进制格式字符串 </returns>
        public static string ToHexadecimaString(this long value)
        {
            return $"0x{value.ToString("x")}";
        }

        /// <summary>
        /// ulong转换为十六进制格式字符串 
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>十六进制格式字符串 </returns>
        public static string ToHexadecimaString(this ulong value)
        {
            return $"0x{value.ToString("x")}";
        }

#if CORE
        /// <summary>
        /// Half转换为十六进制格式字符串 
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>十六进制格式字符串 </returns>
        public static string ToHexadecimaString(this Half value)
        {
            var b = BitConverter.GetBytes(value);
            return $"0x{BitConverter.ToString(b.Reverse().ToArray()).Replace("-", "")}";
        }
#endif

        /// <summary>
        /// ulong转换为十六进制格式字符串 
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>十六进制格式字符串 </returns>
        public static string ToHexadecimaString(this float value)
        {
            var b = BitConverter.GetBytes(value);
            return $"0x{BitConverter.ToString(b.Reverse().ToArray()).Replace("-", "")}";
        }

        /// <summary>
        /// double转换为十六进制格式字符串 
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>十六进制格式字符串 </returns>
        public static string ToHexadecimaString(this double value)
        {
            var b = BitConverter.GetBytes(value);
            return $"0x{BitConverter.ToString(b.Reverse().ToArray()).Replace("-", "")}";
        }

        ///// <summary>
        ///// decimal转换为十六进制格式字符串 
        ///// </summary>
        ///// <param name="value">要转换的值</param>
        ///// <returns>十六进制格式字符串 </returns>
        //public static string ToHexadecimaString(this decimal value)
        //{
        //    var b = BitConverter.GetBytes(value);
        //    return $"0x{BitConverter.ToString(b.Reverse().ToArray()).Replace("-", "")}";
        //}

        ///// <summary>
        ///// ulong转换为十六进制格式字符串 
        ///// </summary>
        ///// <param name="value">要转换的值</param>
        ///// <returns>十六进制格式字符串 </returns>
        //public static string ToHexadecimaString<T>(this T value) where T : struct, IFormattable
        //{
        //    long value2 = 123;
        //    value2.ToString("x");
        //    return $"0x{value.ToString("x", null)}";
        //}


        #endregion


    }
}
